package com.icinfo.cloud.provider.punish.config.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.icinfo.cloud.common.core.Constant.Constant;
import com.icinfo.cloud.provider.common.config.OrgConfig;
import com.icinfo.cloud.provider.common.exception.BusinessException;
import com.icinfo.cloud.provider.punish.config.dto.ConfigOrgRegulatoryDiscretionRuleDto;
import com.icinfo.cloud.provider.punish.config.enums.DiscretionApplyCaseTypeEnum;
import com.icinfo.cloud.provider.punish.config.enums.DiscretionRuleApplyTypeEnum;
import com.icinfo.cloud.provider.punish.config.enums.DiscretionRuleConfigTypeEnum;
import com.icinfo.cloud.provider.punish.config.mapper.ConfigOrgRegulatoryDiscretionRuleMapper;
import com.icinfo.cloud.provider.punish.config.model.ConfigOrgRegulatoryDiscretion;
import com.icinfo.cloud.provider.punish.config.model.ConfigOrgRegulatoryDiscretionRule;
import com.icinfo.cloud.provider.punish.config.model.ConfigOrgRegulatoryDiscretionRuleHis;
import com.icinfo.cloud.provider.punish.config.service.IConfigOrgRegulatoryDiscretionRuleHisService;
import com.icinfo.cloud.provider.punish.config.service.IConfigOrgRegulatoryDiscretionRuleService;
import com.icinfo.cloud.provider.punish.config.service.IConfigOrgRegulatoryDiscretionService;
import com.icinfo.cloud.provider.punish.config.vo.ConfigOrgRegulatoryDiscretionRuleCountVo;
import com.icinfo.cloud.provider.punish.config.vo.ConfigOrgRegulatoryDiscretionRuleVo;
import com.icinfo.cloud.xzcf.provider.member.userinfo.dto.UserDTO;
import com.icinfo.framework.core.service.support.MyBatisServiceSupport;
import com.icinfo.framework.mybatis.mapper.entity.Example;
import com.icinfo.framework.tools.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author HKxxx
 * @date 2024/1/31 15:18
 */
@Slf4j
@Service
public class ConfigOrgRegulatoryDiscretionRuleServiceImpl extends MyBatisServiceSupport implements IConfigOrgRegulatoryDiscretionRuleService {
    @Resource
    private ConfigOrgRegulatoryDiscretionRuleMapper configOrgRegulatoryDiscretionRuleMapper;
    @Resource
    private IConfigOrgRegulatoryDiscretionRuleHisService configOrgRegulatoryDiscretionRuleHisService;
    @Resource
    private IConfigOrgRegulatoryDiscretionService configOrgRegulatoryDiscretionService;
    @Resource
    private OrgConfig orgConfig;

    @Override
    public List<ConfigOrgRegulatoryDiscretionRuleCountVo> getCurrentOrgRuleCountByCatalogIds(List<String> catalogIds) {
        if (CollUtil.isEmpty(catalogIds)) {
            return Collections.emptyList();
        }
        List<ConfigOrgRegulatoryDiscretionRuleCountVo> ruleCountVoList = configOrgRegulatoryDiscretionRuleMapper.getCountsByRegulatoryCatalogId(orgConfig.getSsfj(), catalogIds);
        if (CollUtil.isEmpty(ruleCountVoList)) {
            return Collections.emptyList();
        }
        return ruleCountVoList;
    }

    @Override
    public List<ConfigOrgRegulatoryDiscretionRule> getCurrentOrgRuleByCatalogIds(List<String> catalogIds) {
        if (CollUtil.isEmpty(catalogIds)) {
            return Collections.emptyList();
        }
        //查询市司法局的自由裁量事项违法情形配置
        Example example = new Example(ConfigOrgRegulatoryDiscretionRule.class);
        example.createCriteria()
                .andEqualTo("orgCode", orgConfig.getSsfj())
                .andIn("regulatoryCatalogId", catalogIds);
        return configOrgRegulatoryDiscretionRuleMapper.selectByExample(example);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleDiscretionRuleInfo(ConfigOrgRegulatoryDiscretion discretion,
                                         List<ConfigOrgRegulatoryDiscretionRuleDto> personalRules,
                                         List<ConfigOrgRegulatoryDiscretionRuleDto> orgRules,
                                         DiscretionRuleConfigTypeEnum configType) {
        UserDTO user = getUser();
        // 将前端dto转换为实体类
        List<ConfigOrgRegulatoryDiscretionRule> rules = assembleRuleList(discretion,
                personalRules, orgRules, configType);
        // 对rule表进行修改，并增加历史记录，返回操作行数信息
        int operateRows = operateRuleAndHis(discretion, user, rules);
        if (operateRows < 1) {
            return;
        }
        //当操作行数大于0时，修改主自由裁量配置修改信息
        configOrgRegulatoryDiscretionService.refreshUpdateInfo(discretion.getId());
    }

    @Override
    public List<ConfigOrgRegulatoryDiscretionRuleVo> getByOrgAndApplyTypeAndCatalogId(String orgCode,
                                                                                      DiscretionRuleApplyTypeEnum applyType,
                                                                                      DiscretionApplyCaseTypeEnum applyCaseType,
                                                                                      String catalogId) {
        if (Objects.isNull(applyType) || StrUtil.isEmpty(catalogId)) {
            throw new BusinessException("适用范围类型与事项catalogId不能为空");
        }
        orgCode = Optional.ofNullable(orgCode).orElse(orgConfig.getSsfj());
        Example example = new Example(ConfigOrgRegulatoryDiscretionRule.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orgCode", orgCode)
                .andEqualTo("applyType", applyType.getCode())
                .andEqualTo("regulatoryCatalogId", catalogId);
        //如果来源为PC端 案件调查终结报告违法情形只显示普通程序的情形， APP端不传案件适用类型简易/普通程序展示所有的违法情形
        if (DiscretionApplyCaseTypeEnum.SIMPLE.equals(applyCaseType)) {
            criteria.andEqualTo("applySimple", Constant.STRING_1);
        }
        if (DiscretionApplyCaseTypeEnum.NORMAL.equals(applyCaseType)) {
            criteria.andEqualTo("applyNormal", Constant.STRING_1);
        }
        example.setOrderByClause("sort asc");
        return configOrgRegulatoryDiscretionRuleMapper.selectByExample(example)
                .stream()
                .map(ConfigOrgRegulatoryDiscretionRuleVo::new)
                .collect(Collectors.toList());
    }

    @Override
    public List<ConfigOrgRegulatoryDiscretionRuleVo> getByOrgAndCatalogIdAndApplyTypes(String orgCode,
                                                                                       String catalogId,
                                                                                       List<DiscretionRuleApplyTypeEnum> applyTypes,
                                                                                       DiscretionApplyCaseTypeEnum applyCaseType) {
        if (CollUtil.isEmpty(applyTypes) || StrUtil.isEmpty(catalogId)) {
            throw new BusinessException("适用范围类型集合与事项catalogId不能为空");
        }
        orgCode = Optional.ofNullable(orgCode).orElse(getUser().getOrgCode());
        Example example = new Example(ConfigOrgRegulatoryDiscretionRule.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orgCode", orgCode)
                .andIn("applyType", applyTypes.stream().map(DiscretionRuleApplyTypeEnum::getCode).collect(Collectors.toList()))
                .andEqualTo("regulatoryCatalogId", catalogId);
        if (DiscretionApplyCaseTypeEnum.SIMPLE.equals(applyCaseType)) {
            criteria.andEqualTo("applySimple", Constant.STRING_1);
        }
        if (DiscretionApplyCaseTypeEnum.NORMAL.equals(applyCaseType)) {
            criteria.andEqualTo("applyNormal", Constant.STRING_1);
        }
        example.setOrderByClause("sort asc");
        return configOrgRegulatoryDiscretionRuleMapper.selectByExample(example)
                .stream()
                .map(rule -> {
                    ConfigOrgRegulatoryDiscretionRuleVo vo = new ConfigOrgRegulatoryDiscretionRuleVo(rule);
                    //转换规则名称 例如（个人）XXXX || （单位）XXXX
                    vo.setRuleName(String.format("(%s)%s",
                            DiscretionRuleApplyTypeEnum.getByCode(rule.getApplyType()).getDesc(),
                            rule.getRuleName()));
                    return vo;
                })
                .collect(Collectors.toList());
    }

    /**
     * 操作规则表 并新增历史记录
     *
     * @param discretion
     * @param user
     * @param ruleList
     * @return 操作行数
     */
    private int operateRuleAndHis(ConfigOrgRegulatoryDiscretion discretion, UserDTO user,
                                  List<ConfigOrgRegulatoryDiscretionRule> ruleList) {
        int operateRows = 0;
        // 得到已存在的rule信息列表
        Example ruleExample = new Example(ConfigOrgRegulatoryDiscretionRule.class);
        ruleExample.createCriteria().andEqualTo("discretionId", discretion.getId());
        //查询并构建 key->规则id value->规则对象的数据
        List<ConfigOrgRegulatoryDiscretionRule> oldRules = configOrgRegulatoryDiscretionRuleMapper.selectByExample(ruleExample);
        Map<String, ConfigOrgRegulatoryDiscretionRule> oldRuleMap = oldRules
                .stream().collect(Collectors.toMap(ConfigOrgRegulatoryDiscretionRule::getId, Function.identity()));

        //筛选出待比较修改的数据
        List<ConfigOrgRegulatoryDiscretionRule> waitCompareRuleList = ruleList.stream()
                .filter(t -> StrUtil.isNotEmpty(t.getId())).collect(Collectors.toList());

        //id为null的代表需要新增的数据
        List<ConfigOrgRegulatoryDiscretionRule> addRuleList = ruleList.stream()
                .filter(t -> StrUtil.isEmpty(t.getId()))
                .collect(Collectors.toList());
        insertRuleList(user, addRuleList);
        //新增行数
        operateRows += addRuleList.size();

        //删除规则，并增加删除行数
        operateRows += removeRules(oldRules, waitCompareRuleList);

        // 比较并修改数据
        List<ConfigOrgRegulatoryDiscretionRule> updateRuleList = waitCompareRuleList.stream()
                .filter(after -> compareAndModifyRuleAndHasHis(oldRuleMap.get(after.getId()), after, user.getRealName()))
                .collect(Collectors.toList());
        //操作行数增加修改的行数
        operateRows += updateRuleList.size();

        //组合待插入his表数据的规则，新增的数据&修改的数据
        LinkedList<ConfigOrgRegulatoryDiscretionRule> waitInsertHisRule = new LinkedList<>(addRuleList);
        waitInsertHisRule.addAll(updateRuleList);
        //增加历史记录
        configOrgRegulatoryDiscretionRuleHisService.insertBatch(convertRuleHisList(waitInsertHisRule));
        //返回操作行数
        return operateRows;
    }

    /**
     * 转换为rule实体类
     *
     * @param discretion    自由裁量配置
     * @param personalRules 个人规则集合
     * @param orgRules      单位规则集合
     * @param configType    裁量标准
     * @return 转换的实体类
     */
    public List<ConfigOrgRegulatoryDiscretionRule> assembleRuleList(ConfigOrgRegulatoryDiscretion discretion,
                                                                    List<ConfigOrgRegulatoryDiscretionRuleDto> personalRules,
                                                                    List<ConfigOrgRegulatoryDiscretionRuleDto> orgRules,
                                                                    DiscretionRuleConfigTypeEnum configType) {

        LinkedList<ConfigOrgRegulatoryDiscretionRule> ruleList = new LinkedList<>();
        //转换个人规则为实体类
        for (int i = 0; i < personalRules.size(); i++) {
            ConfigOrgRegulatoryDiscretionRule rule = personalRules.get(i)
                    .convertRule(discretion, DiscretionRuleApplyTypeEnum.PERSONAL, configType);
            rule.setSort((long) i + 1);
            ruleList.add(rule);
        }
        //转换单位规则为实体类
        for (int i = 0; i < orgRules.size(); i++) {
            ConfigOrgRegulatoryDiscretionRule rule = orgRules.get(i)
                    .convertRule(discretion, DiscretionRuleApplyTypeEnum.ORG, configType);
            rule.setSort((long) i + 1);
            ruleList.add(rule);
        }
        return ruleList;
    }

    /**
     * 转换规则历史表数据
     *
     * @param rules 违法情形列表
     * @return 违法情形历史数据
     */
    private List<ConfigOrgRegulatoryDiscretionRuleHis> convertRuleHisList(List<ConfigOrgRegulatoryDiscretionRule> rules) {
        return rules.stream().map(this::convertHis)
                .collect(Collectors.toList());
    }


    /**
     * 转换为历史表数据
     *
     * @param rule 违法情形实体类
     * @return 违法情形历史数据
     */
    private ConfigOrgRegulatoryDiscretionRuleHis convertHis(ConfigOrgRegulatoryDiscretionRule rule) {
        ConfigOrgRegulatoryDiscretionRuleHis his = new ConfigOrgRegulatoryDiscretionRuleHis();
        his.setId(StringUtils.uuid());
        his.setRuleId(rule.getId());
        his.setRuleHisId(rule.getRuleHisId());
        his.setDiscretionId(rule.getDiscretionId());
        his.setOrgCode(rule.getOrgCode());
        his.setConfigType(rule.getConfigType());
        his.setRegulatoryCatalogId(rule.getRegulatoryCatalogId());
        his.setApplyType(rule.getApplyType());
        his.setRuleName(rule.getRuleName());
        his.setRuleType(rule.getRuleType());
        his.setLowerLimitAmount(rule.getLowerLimitAmount());
        his.setUpperLimitAmount(rule.getUpperLimitAmount());
        his.setFixAmount(rule.getFixAmount());
        his.setGradeLevel(rule.getGradeLevel());
        his.setPunishKinds(rule.getPunishKinds());
        his.setCreateTime(rule.getUpdateTime());
        his.setCreateUser(rule.getUpdateUser());
        return his;
    }

    /**
     * 批量插入违法情形
     *
     * @param user        当前用户信息
     * @param addRuleList 新增规则集合
     */
    private void insertRuleList(UserDTO user, List<ConfigOrgRegulatoryDiscretionRule> addRuleList) {
        if (CollUtil.isEmpty(addRuleList)) {
            return;
        }
        //生成初始化新增数据
        for (ConfigOrgRegulatoryDiscretionRule rule : addRuleList) {
            Date now = new Date();
            rule.setId(StringUtils.uuid());
            rule.setCreateTime(new Date());
            rule.setCreateUser(user.getRealName());
            rule.setUpdateTime(now);
            rule.setUpdateUser(user.getRealName());
        }
        configOrgRegulatoryDiscretionRuleMapper.insertBatch(addRuleList);
    }

    /**
     * 移除规则
     *
     * @param oldRules
     * @param waitCompareRuleList
     * @return 操作行数
     */
    private int removeRules(List<ConfigOrgRegulatoryDiscretionRule> oldRules, List<ConfigOrgRegulatoryDiscretionRule> waitCompareRuleList) {
        // 得到需要删除的信息（数据库已有数据集合与前端数据集合的差集）
        //历史数据id集合
        List<String> oldIdList = oldRules.stream()
                .map(ConfigOrgRegulatoryDiscretionRule::getId).collect(Collectors.toList());
        //待比较的规则id集合
        List<String> waitCompareRuleIdList = waitCompareRuleList.stream()
                .map(ConfigOrgRegulatoryDiscretionRule::getId).collect(Collectors.toList());
        Collection<String> waitDeleteRuleIdList = CollUtil.disjunction(oldIdList, waitCompareRuleIdList);
        if (CollUtil.isEmpty(waitDeleteRuleIdList)) {
            return 0;
        }
        Example example = new Example(ConfigOrgRegulatoryDiscretionRule.class);
        example.createCriteria().andIn("id", waitDeleteRuleIdList);
        return configOrgRegulatoryDiscretionRuleMapper.deleteByExample(example);
    }

    /**
     * 比较修改返回是否增加his记录,排除(applySimple、applyNormal、sort)
     *
     * @param before 数据库原本的数据
     * @param after  前端修改之后的数据
     * @return 是否需要增加his记录 true:需要增加 false:不需要
     */
    private boolean compareAndModifyRuleAndHasHis(ConfigOrgRegulatoryDiscretionRule before, ConfigOrgRegulatoryDiscretionRule after, String updateUser) {
        // 判断对象是否有变化
        if (equals(before, after)) {
            return Boolean.FALSE;
        }
        after.setCreateTime(before.getCreateTime());
        after.setCreateUser(before.getCreateUser());
        after.setUpdateTime(new Date());
        after.setUpdateUser(updateUser);
        if (isAddHis(before, after)) {
            // 如果只是修改了排序/适用类型，则不需要重新生成his表，也不能修改ruleHisId
            after.setRuleHisId(null);
            configOrgRegulatoryDiscretionRuleMapper.updateByPrimaryKeySelective(after);
            return Boolean.FALSE;
        }
        configOrgRegulatoryDiscretionRuleMapper.updateByPrimaryKey(after);
        return Boolean.TRUE;
    }

    /**
     * 比较rule信息是否被修改
     *
     * @param before 数据库中的数据
     * @param after  前端数据
     * @return
     */
    public boolean equals(ConfigOrgRegulatoryDiscretionRule before, ConfigOrgRegulatoryDiscretionRule after) {
        if (before == after) {
            return true;
        }
        if (Objects.isNull(before) || Objects.isNull(after)) {
            return false;
        }
        if (before.getClass() != after.getClass()) {
            return false;
        }
        return (before.getId() == null ? after.getId() == null : before.getId().equals(after.getId()))
                && (before.getDiscretionId() == null ? after.getDiscretionId() == null : before.getDiscretionId().equals(after.getDiscretionId()))
                && (before.getOrgCode() == null ? after.getOrgCode() == null : before.getOrgCode().equals(after.getOrgCode()))
                && (before.getConfigType() == null ? after.getConfigType() == null : before.getConfigType().equals(after.getConfigType()))
                && (before.getRegulatoryCatalogId() == null ? after.getRegulatoryCatalogId() == null : before.getRegulatoryCatalogId().equals(after.getRegulatoryCatalogId()))
                && (before.getApplyType() == null ? after.getApplyType() == null : before.getApplyType().equals(after.getApplyType()))
                && (before.getRuleName() == null ? after.getRuleName() == null : before.getRuleName().equals(after.getRuleName()))
                && (before.getRuleType() == null ? after.getRuleType() == null : before.getRuleType().equals(after.getRuleType()))
                && (before.getLowerLimitAmount() == null ? after.getLowerLimitAmount() == null : before.getLowerLimitAmount().equals(after.getLowerLimitAmount()))
                && (before.getUpperLimitAmount() == null ? after.getUpperLimitAmount() == null : before.getUpperLimitAmount().equals(after.getUpperLimitAmount()))
                && (before.getFixAmount() == null ? after.getFixAmount() == null : before.getFixAmount().equals(after.getFixAmount()))
                && (before.getApplySimple() == null ? after.getApplySimple() == null : before.getApplySimple().equals(after.getApplySimple()))
                && (before.getApplyNormal() == null ? after.getApplyNormal() == null : before.getApplyNormal().equals(after.getApplyNormal()))
                && (before.getGradeLevel() == null ? after.getGradeLevel() == null : before.getGradeLevel().equals(after.getGradeLevel()))
                && (before.getPunishKinds() == null ? after.getPunishKinds() == null : before.getPunishKinds().equals(after.getPunishKinds()))
                && (before.getSort() == null ? after.getSort() == null : before.getSort().equals(after.getSort()));
    }

    /**
     * 是否增加his记录(applySimple、applyNormal、sort)是否被修改
     *
     * @param before 数据库中的数据
     * @param after  前端数据
     * @return true 需要  false 不需要
     */
    public boolean isAddHis(ConfigOrgRegulatoryDiscretionRule before, ConfigOrgRegulatoryDiscretionRule after) {
        if (before == after) {
            return true;
        }
        if (Objects.isNull(before) || Objects.isNull(after)) {
            return false;
        }
        if (before.getClass() != after.getClass()) {
            return false;
        }
        return (before.getId() == null ? after.getId() == null : before.getId().equals(after.getId()))
                && (before.getDiscretionId() == null ? after.getDiscretionId() == null : before.getDiscretionId().equals(after.getDiscretionId()))
                && (before.getOrgCode() == null ? after.getOrgCode() == null : before.getOrgCode().equals(after.getOrgCode()))
                && (before.getConfigType() == null ? after.getConfigType() == null : before.getConfigType().equals(after.getConfigType()))
                && (before.getRegulatoryCatalogId() == null ? after.getRegulatoryCatalogId() == null : before.getRegulatoryCatalogId().equals(after.getRegulatoryCatalogId()))
                && (before.getApplyType() == null ? after.getApplyType() == null : before.getApplyType().equals(after.getApplyType()))
                && (before.getRuleName() == null ? after.getRuleName() == null : before.getRuleName().equals(after.getRuleName()))
                && (before.getRuleType() == null ? after.getRuleType() == null : before.getRuleType().equals(after.getRuleType()))
                && (before.getLowerLimitAmount() == null ? after.getLowerLimitAmount() == null : before.getLowerLimitAmount().equals(after.getLowerLimitAmount()))
                && (before.getUpperLimitAmount() == null ? after.getUpperLimitAmount() == null : before.getUpperLimitAmount().equals(after.getUpperLimitAmount()))
                && (before.getGradeLevel() == null ? after.getGradeLevel() == null : before.getGradeLevel().equals(after.getGradeLevel()))
                && (before.getPunishKinds() == null ? after.getPunishKinds() == null : before.getPunishKinds().equals(after.getPunishKinds()))
                && (before.getFixAmount() == null ? after.getFixAmount() == null : before.getFixAmount().equals(after.getFixAmount()));
    }


}
